/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
define(["require", "exports", "../protocol.const", "../utils/convert"], function (require, exports, PConst, convert_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const outlineTypeTable = Object.create(null);
    class TypeScriptDocumentSymbolProvider {
        constructor(client, vscode) {
            this.client = client;
            this.vscode = vscode;
            outlineTypeTable[PConst.Kind.module] = this.vscode.SymbolKind.Module;
            outlineTypeTable[PConst.Kind.class] = this.vscode.SymbolKind.Class;
            outlineTypeTable[PConst.Kind.enum] = this.vscode.SymbolKind.Enum;
            outlineTypeTable[PConst.Kind.interface] = this.vscode.SymbolKind.Interface;
            outlineTypeTable[PConst.Kind.memberFunction] = this.vscode.SymbolKind.Method;
            outlineTypeTable[PConst.Kind.memberVariable] = this.vscode.SymbolKind.Property;
            outlineTypeTable[PConst.Kind.memberGetAccessor] = this.vscode.SymbolKind.Property;
            outlineTypeTable[PConst.Kind.memberSetAccessor] = this.vscode.SymbolKind.Property;
            outlineTypeTable[PConst.Kind.variable] = this.vscode.SymbolKind.Variable;
            outlineTypeTable[PConst.Kind.const] = this.vscode.SymbolKind.Variable;
            outlineTypeTable[PConst.Kind.localVariable] = this.vscode.SymbolKind.Variable;
            outlineTypeTable[PConst.Kind.variable] = this.vscode.SymbolKind.Variable;
            outlineTypeTable[PConst.Kind.function] = this.vscode.SymbolKind.Function;
            outlineTypeTable[PConst.Kind.localFunction] = this.vscode.SymbolKind.Function;
        }
        provideDocumentSymbols(resource, token) {
            return __awaiter(this, void 0, void 0, function* () {
                const filepath = this.client.normalizePath(resource.uri);
                if (!filepath) {
                    return [];
                }
                const args = {
                    file: filepath
                };
                try {
                    const result = [];
                    if (this.client.apiVersion.has206Features()) {
                        const response = yield this.client.execute('navtree', args, token);
                        if (response.body) {
                            // The root represents the file. Ignore this when showing in the UI
                            let tree = response.body;
                            if (tree.childItems) {
                                tree.childItems.forEach((item) => TypeScriptDocumentSymbolProvider.convertNavTree(resource.uri, result, item, this.vscode));
                            }
                        }
                    }
                    else {
                        const response = yield this.client.execute('navbar', args, token);
                        if (response.body) {
                            let foldingMap = Object.create(null);
                            response.body.forEach((item) => TypeScriptDocumentSymbolProvider.convertNavBar(resource.uri, 0, foldingMap, result, item, this.vscode));
                        }
                    }
                    return result;
                }
                catch (e) {
                    return [];
                }
            });
        }
        static convertNavBar(resource, indent, foldingMap, bucket, item, vscode, containerLabel) {
            let realIndent = indent + item.indent;
            let key = `${realIndent}|${item.text}`;
            if (realIndent !== 0 && !foldingMap[key] && TypeScriptDocumentSymbolProvider.shouldInclueEntry(item.text)) {
                let result = new vscode.SymbolInformation(item.text, outlineTypeTable[item.kind] || vscode.SymbolKind.Variable, containerLabel ? containerLabel : '', new vscode.Location(resource, convert_1.tsTextSpanToVsRange(item.spans[0], vscode)));
                foldingMap[key] = result;
                bucket.push(result);
            }
            if (item.childItems && item.childItems.length > 0) {
                for (let child of item.childItems) {
                    TypeScriptDocumentSymbolProvider.convertNavBar(resource, realIndent + 1, foldingMap, bucket, child, item.text);
                }
            }
        }
        static convertNavTree(resource, bucket, item, vscode, containerLabel) {
            const result = new vscode.SymbolInformation(item.text, outlineTypeTable[item.kind] || vscode.SymbolKind.Variable, containerLabel ? containerLabel : '', new vscode.Location(resource, convert_1.tsTextSpanToVsRange(item.spans[0], vscode)));
            if (item.childItems && item.childItems.length > 0) {
                for (const child of item.childItems) {
                    TypeScriptDocumentSymbolProvider.convertNavTree(resource, bucket, child, result.name);
                }
            }
            if (TypeScriptDocumentSymbolProvider.shouldInclueEntry(result.name)) {
                bucket.push(result);
            }
        }
        static shouldInclueEntry(name) {
            return !!(name && name !== '<function>' && name !== '<class>');
        }
    }
    exports.default = TypeScriptDocumentSymbolProvider;
});
